<html>
    <head>
        <title>响应事件</title>
    </head>
    <body>
        <script>
            // 响应事件

                    /*
                                React允许你想JSX添加事件处理程序。
                                事件处理程序就是你自己写的函数，将被触发以响应用户交互。（单击、悬停、聚焦等）
                            */
                            
                            /*
                                像<button>这样的内置组件，只支持像onClick这样的"浏览器内置事件"。
                                但是，你也可以创建自己的组件，并为它们的事件处理程序提供你喜欢的任何特定于应用的名称。
                            */
                                 // eg:  在一个组件js文件中:

                                 function Button({onClick,children}){
                                            return (
                                                <Button onClick={onClick}>
                                                    {children}
                                                </Button>
                                            );
                                        }

                                        function Toolbar({onPlayMovie,onUploadImage}){
                                            return(
                                                <div>
                                                      <Button onClick={onPlayMove}>
                                                           Play Movie
                                                      </Button>
                                                      <Button onClick={onUploadImage}>
                                                           Upload Image
                                                      </Button>
                                                </div>
                                            );
                                        }

                                        // 默认导出app组件
                                        export default function App(){
                                            return (
                                                <Toolbar 
                                                        onPlayMoive={()=>alert('Playing')}
                                                        onUploadImage={()=>alert('onUploadImage')}  
                                                />
                                            );
                                        }

                    //一、添加事件处理程序
                                /*
                                        要添加事件处理程序，你要首先定义一个函数，然后"将函数作为prop(属性)"传递到适当的JSX标记。
                                */
                                        // eg:这是一个尚未执行任何操作的按钮：
                                            export default function Button(){
                                                return (
                                                    <Button>
                                                        Click Me
                                                    </Button>
                                                )
                                            }

                                        /*
                                            你可以安装以下三个步骤使其在用户单击是显示消息：

                                                ①、在button组件中声明一个名为 handleClick的函数
                                                ②、在该 handleClick函数中实现显示消息的逻辑
                                                ③、将onClick={handleClick} 添加大<button> JSX
                                        */
                                        // eg:
                                            export default function Button(){
                                                function handleClick(){
                                                    alert('You clicked me !');
                                                }

                                                return (
                                                    <Button onClick ={handleClick}>
                                                        Click Me
                                                    </Button>
                                                );
                                            }
                                        /*
                                            上面例子中，你定义了handleClick函数，然后将它"作为onClick属性" 把它传递给<button>组件。

                                            所以，事件处理函数：
                                                ①、通常在你的组件内部定义。
                                                ②、名称以"handle"开头，后面跟上事件名称。    
                                        */
                                        /*
                                            或者，你可以在JSX中内联声明事件处理程序：
                                        */
                                            // eg:
                                                export default function Button(){
                                                    return(
                                                        <Button onClick={()=>alert('You clicked me !')}>
                                                        </Button>
                                                    );
                                                }

                                        /*
                                            注意：
                                                传递给事件处理程序的函数"必须被传递"，而"不是被调用"

                                                正确：
                                                    <button onClick={handleClick}>Click Me</button>

                                                错误：
                                                    <button onClick={handleClick()}>Click Me</button>

                                                    如果直接调用，那组件在渲染时就会调用handleClick，而不是在用户点击按钮的时候。
                                            
                                                如果你想内联定义事件处理程序，请将函数定封账在"匿名函数"中：

                                                    <button onClick={()=>{alert('You clicked me !')}}>Click Me</button>

                                        */

                    // 二、在事件处理程序中读取属性
                                /*
                                    因为事件处理程序是在组件内部声明的，所以它们可以访问组件的属性。
                                */
                                    // eg:
                                    function AlterButton({message,children}){
                                        return (
                                            // 事件处理函数中 可以直接访问组件属性
                                            <Button onClick={()=>alert(message)}> 
                                                {children}
                                            </Button>
                                        );
                                    }

                                    export default function Toolbar(){
                                        return(
                                            <div>
                                                <AlterButton message="Playing!">
                                                    Play Movie
                                                </AlterButton>
                                                <AlterButton message="Uploading!">
                                                    Upload Image
                                                </AlterButton>
                                            </div>
                                        );
                                    }

                    // 三、将事件处理程序"作为属性" 传递
                            /*
                                通常你会希望父级组加你指定子级组件的事件处理程序。
                                考虑按钮组件，根据你使用按钮的位置，你可能希望它执行不同的功能，也许会播放电影，另一个按钮会上传图片。

                                为此，传递组件从其父组件接收的属性作为事件处理程序：
                            */
                                    // eg: app.js文件：
                                    function Button({onClick,children}){
                                        // 使用父组件"以属性形式传递过来的"事件处理程序
                                        return(
                                            <Button onClick={onClick}>
                                                {children}
                                            </Button>
                                        );
                                    }

                                    function PlayButton({movieName}){
                                        function handlePlayClick(){
                                            alert('Playin g ${moiveName} !');
                                        }

                                        // "以属性的形式"给子组件传递事件处理程序
                                        return (
                                            <Button onClick={handlePlayClick}>
                                                Play
                                            </Button>
                                        );
                                    }

                                    function UploadButton(){
                                        // "以属性的形式"给子组件传递事件处理程序(内联声明)
                                        return (
                                            <Button onClick={()=>alert('Uploading...')}>
                                                Upload Image
                                            </Button>
                                        );
                                    }

                                    export default function Toolbar(){
                                        return(
                                            <div>
                                                <PlayButton movieName="Kiki" />
                                                <UploadButton />
                                            </div>
                                        );
                                    }

                    
                    // 四、命名事件处理程序属性
                            /*
                                <button> 和 <div> 等内置组件"仅支持浏览器事件名称",如 onClick.
                                但是，当你构建自己的组件时，你可以按照自己喜欢的方式命名它们的"事件处理程序属性"

                                但是，按照惯例：   事件处理程序属性应该以 "on" 开头，后面跟大写字母。
                            */
                                    // eg:
                                    function Button({onSmash,children}){
                                        return (
                                            <Button onClick={onSmash}> 
                                                {children}
                                            </Button>
                                        );
                                    }

                                    export default function App(){
                                        return (
                                            <div>
                                                <Button onSmash={()=>alert('Smash!')}>
                                                    Play Movie
                                                </Button>
                                                <Button onSmash={()=>alert('Uploading...')}>
                                                    Upload Image
                                                </Button>
                                            </div>
                                        );
                                    }

                            /*
                                当你的组件支持多种交互时，你可以为特定于应用的概念命名事件处理程序属性。
                            */
                                    // eg: 这个 Toolbar 组件接收 onPlayMovie 和 onUploadImage 事件处理程序：
                                    function Button({onClick,children}){
                                        return (
                                            <Button onClick={onClick}>
                                                {children}
                                            </Button>
                                        );
                                    }

                                    function Toolbar({onPlayMoive,onUploadImage}){
                                        return (
                                            <div>
                                                <Button onClick={onPlayMoive}>
                                                    Play Movie
                                                </Button>
                                                <Button onClick={onUploadImage}>
                                                    Upload Image
                                                </Button>
                                            </div>
                                        )
                                    }

                                    export default function App(){
                                        // 在"父组件"中，给子组件的"事件处理程序属性"传递事件处理程序(注意，是传递"一个函数的定义"，而不是"调用这个函数")
                                        return (
                                            <Toolbar 
                                                    onPlayMoive={()=>alert('Playing!') }
                                                    onUploadImage={()=>alert('Uploading....')}
                                            />
                                        );
                                    }

                                    /*
                                        注意，app组件不需要知道Toolbar如何使用传递过去的事件处理程序。
                                        这是Toolbar组件的"内部细节"。
                                        （这里，Toolblar 把它绑在子的子组件<Button>的onClick属性上，但是Toolbar 可以将其绑定到任何组件的任何"事件处理程序属性"上）
                                    */

                    // 五、事件传播(事件冒泡)
                            /*
                                事件处理程序还将捕获来自你组件可能具有的"任何子组件的事件"。
                                这就是，我们说事件在"事件树"上"冒泡"或"传播" ：  它从事件发生的地方开始，然后沿着树上升。
                            */
                                  // eg:  这个<div>中包含两个按钮，<div>和每个按钮都有自己的 onClick处理程序。 你认为单击按钮时会触发那些处理程序？
                                        export default function Toolbar(){
                                            return (
                                                <div onClick={()=>{alert('You  clicked on the toolbar!')}}>
                                                    <Button onClick={()=>alert('Playing')}>
                                                        Play Movie
                                                    </Button>
                                                    <Button onClick={()=>{alert('Uploading...')}}>
                                                        Upload Image    
                                                    </Button>
                                                </div>
                                            );
                                        }
                                  /*
                                      答案是： 如果你单击任何一个按钮，它的onClick属性对应的处理程序会首先被执行，然后父组件的onClick属性对应的事件处理程序也会执行。
                                              如果你单击Toolbar本身，没接触到按钮，那就只有父组件的事件处理程序会被执行。
                                  */

                            // 1、阻止事件传播
                                        /*
                                            事件处理程序只接受"事件对象"作为其"唯一的参数"。按照惯例，它通常被称为 "e" 代表 "event" .
                                            你可以使用此对象来读取有关事件的信息。
                                            该"事件对象"还允许你停止事件传播(冒泡)。
                                        */
                                            // eg:  如果你想阻止事件到达父组件，你需要想<button>组件那样调用 e.stopPropagation()
                                                function Button({ onClick, children }) {
                                                    return (
                                                        <button onClick={e => {
                                                                                e.stopPropagation();
                                                                                onClick();
                                                                               }}>
                                                                {children}
                                                        </button>
                                                    );
                                                }
                                                export default function Toolbar() {
                                                    return (
                                                            <div className="Toolbar" onClick={() => {alert('You clicked on the toolbar!');}}>
                                                                <Button onClick={() => alert('Playing!')}>
                                                                    Play Movie
                                                                </Button>
                                                                <Button onClick={() => alert('Uploading!')}>
                                                                    Upload Image
                                                                </Button>
                                                            </div>
                                                    );
                                                }
                                    
                            // 2、传递处理程序作为"事件冒泡的替代方案"
                                        /*
                                            如果你不想让子组件的事件冒泡，但是呢还想在父组件给定义子组件"一旦触发某个事件"就做响应的处理。
                                            你可以在调用父组件的onClick处理程序前，阻止事件冒泡，然后调用父组件传递过来的处理程序。
                                            这样，可以让子组件处理事件，同时也可以让父组件给子组件的事件"指定一些额外的处理行为"。

                                            与传播(冒泡)不同，它不是自动的。但这种模式好处是，你可以清除地跟踪作为摸狗事件的结果执行的这个代码链。
                                        */

                    
                    // 六、阻止默认行为
                            /*
                                某些浏览器事件具有与之相关联的"默认行为"。例如， <form>提交事件，当点击其中的按钮时发生，默认情况下会加载整个页面。
                            */
                                    export default function Signup(){
                                        return (
                                            <form onSubmit={()=>{alert('Submit!')}}>
                                                <input/>
                                                <button>Send</button>
                                            </form>
                                        )
                                    }

                            // 然而，你可以在事件处理程序上调用 e.preventDefault()来阻止默认行为的发生。
                                   // eg:
                                   export default function Signup(){
                                        return (
                                            <form onSubmit={()=>{
                                                                    e.preventDefault();
                                                                    alert('Submit!')
                                                                }
                                                           }>
                                                <input/>
                                                <button type="Submit">Send</button>
                                            </form>
                                        );
                                   }

                            /*
                                注意： 不要混淆  e.preventDefault() 和 e.stopPropagation()
                                    一个是阻止"浏览器默认行为"  一个是阻止"事件冒泡"
                            */


                    // 七、事件处理程序可以有副作用吗？
                            /*
                                   绝对地！
                                   事件处理程序是处理副作用的"最佳场地"。
                            */
        </script>
    </body>
</html>